/********************************************************************************************************
 * @file    ota.h
 *
 * @brief   This is the header file for BLE SDK
 *
 * @author  BLE GROUP
 * @date    06,2022
 *
 * @par     Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *
 *******************************************************************************************************/
#ifndef OTA_H_
#define OTA_H_


/**
 * @brief   Legacy OTA command
 */
#define CMD_OTA_VERSION 0xFF00 //client -> server
#define CMD_OTA_START   0xFF01 //client -> server
#define CMD_OTA_END     0xFF02 //client -> server

/**
 * @brief   Extended OTA command
 */
#define CMD_OTA_START_EXT        0xFF03 //client -> server
#define CMD_OTA_FW_VERSION_REQ   0xFF04 //client -> server
#define CMD_OTA_FW_VERSION_RSP   0xFF05 //server -> client
#define CMD_OTA_RESULT           0xFF06 //server -> client
#define CMD_OTA_SCHEDULE_PDU_NUM 0xFF08 //server -> client
#define CMD_OTA_SCHEDULE_FW_SIZE 0xFF09 //server -> client


/**
 * @brief   public key & signature for secure boot
 * for MCU support secure boot function, client send public key & signature
 * by OTA command FF10 ~ FF17, total 16 byte *8 = 128 byte
 */
#define CMD_OTA_SB_PUBKEY_SIGN_MIN 0xFF10 //client -> server
#define CMD_OTA_SB_PUBKEY_SIGN_MAX 0xFF17 //client -> server

/**
 * @brief   OTA result
 */
enum
{
    //0x00
    OTA_SUCCESS = 0,         //success
    OTA_DATA_PACKET_SEQ_ERR, //OTA data packet sequence number error: repeated OTA PDU or lost some OTA PDU
    OTA_PACKET_INVALID,      //invalid OTA packet: 1. invalid OTA command; 2. addr_index out of range; 3.not standard OTA PDU length
    OTA_DATA_CRC_ERR,        //packet PDU CRC err

    //0x04
    OTA_WRITE_FLASH_ERR, //write OTA data to flash ERR
    OTA_DATA_INCOMPLETE, //lost last one or more OTA PDU
    OTA_FLOW_ERR,        //peer device send OTA command or OTA data not in correct flow
    OTA_FW_CHECK_ERR,    //firmware CRC check error

    //0x08
    OTA_VERSION_COMPARE_ERR, //the version number to be update is lower than the current version
    OTA_PDU_LEN_ERR,         //PDU length error: not 16*n, or not equal to the value it declare in "CMD_OTA_START_EXT" packet
    OTA_FIRMWARE_MARK_ERR,   //firmware mark error: not generated by telink's BLE SDK
    OTA_FW_SIZE_ERR,         //firmware size error: no firmware_size; firmware size too small or too big

    //0x0C
    OTA_DATA_PACKET_TIMEOUT,              //time interval between two consequent packet exceed a value(user can adjust this value)
    OTA_TIMEOUT,                          //OTA flow total timeout
    OTA_FAIL_DUE_TO_CONNECTION_TERMINATE, //OTA fail due to current connection terminate(maybe connection timeout or local/peer device terminate connection)
    OTA_MCU_NOT_SUPPORTED,                //MCU does not support this OTA mode

    //0x10
    OTA_LOGIC_ERR,                             //software logic error, please contact FAE of Telink

    OTA_FW_FLASH_PROT_NEW_FW_NOT_MATCH_OLD_FW, //firmware flash protection function: new firmware not match old firmware
                                               //old firmware enable firmware flash protection, but new firmware do not enable
                                               //Attention: old firmware do not enable but new firmware enable, this is allowed.

    /* only secure boot mode involved from 0x80 */
    OTA_SECBOOT_HW_ERR = 0x80,           //OTA server device hardware error
    OTA_SECBOOT_SYSTEM_ERR,              //OTA server device system error
    OTA_SECBOOT_FUNC_NOT_ENABLE,         //OTA server device do not enable secure boot function
    OTA_SECBOOT_PUBKEY_SIGN_SEQ_ERR,     //OTA public key & signature sequence number error: repeated or lost
    OTA_SECBOOT_PUBKEY_SIGN_LEN_ERR,     //OTA public key & signature data packet length error
    OTA_SECBOOT_PUBLIC_KEY_ERR,          //OTA client public key not match OTA server device local hash
    OTA_SECBOOT_SIGN_VERIFY_FAIL,        //OTA signature verification fail
    OTA_SECBOOT_WRITE_DESC_FAIL,         //write secure boot descriptor fail
    OTA_SECBOOT_NEW_FW_NOT_MATCH_OLD_FW, //secure boot function: new firmware not match old firmware
                                         //1.  old firmware enable secure boot, but new firmware do not enable
                                         //2.  old firmware do not enable secure boot, but new firmware enable
    OTA_FWENC_NEW_FW_NOT_MATCH_OLD_FW,   //firmware encryption function: new firmware not match old firmware
                                         //1.  old firmware enable firmware encryption, but new firmware do not enable
                                         //2.  old firmware do not enable firmware encryption, but new firmware enable
};

/**
 *  @brief data structure of OTA command "CMD_OTA_START"
 */
typedef struct
{
    u16 ota_cmd;
} ota_start_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_END"
 */
typedef struct
{
    u16 ota_cmd;
    u16 adr_index_max;
    u16 adr_index_max_xor;
} ota_end_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_START_EXT"
 */
typedef struct
{
    u16 ota_cmd;
    u8  pdu_length;      //must be: 16*n(n is in range of 1 ~ 15); pdu_length: 16,32,48,...240
    u8  version_compare; //0: no version compare; 1: only higher version can replace lower version
    u8  rsvd[16];        //reserved for future use
} ota_startExt_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_RESULT"
 */
typedef struct
{
    u16 ota_cmd;
    u8  result;
    u8  rsvd;
} ota_result_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_FW_VERSION_REQ"
 */
typedef struct
{
    u16 ota_cmd;
    u16 version_num;
    u8  version_compare; //1: only higher version can replace lower version
} ota_versionReq_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_FW_VERSION_RSP"
 */
typedef struct
{
    u16 ota_cmd;
    u16 version_num;
    u8  version_accept; //1: accept firmware update; 0: reject firmware update(version compare enable, and compare result: fail)
} ota_versionRsp_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_SCHEDULE_PDU_NUM"
 */
typedef struct
{
    u16 ota_cmd;
    u16 success_pdu_cnt; // successful OTA PDU number
} ota_sche_pdu_num_t;

/**
 *  @brief data structure of OTA command "CMD_OTA_SCHEDULE_FW_SIZE"
 */
typedef struct
{
    u16 ota_cmd;
    u32 success_fw_size; // successful OTA firmware size (unit: Byte)
} ota_sche_fw_size_t;

/**
 * @brief      ota crc32 related function.
 * @param[in]  crc: initial crc value.
 * @param[in]  input: input data.
 * @param[in]  table: crc calculate table.
 * @param[in]  len: data length.
 * @return     crc result.
 */
unsigned long crc32_half_cal(unsigned long crc, unsigned char *input, unsigned long *table, int len);

/**
 * @brief      ota crc32 related function.
 * @param[in]  crc: initial crc value.
 * @param[in]  input: input data.
 * @param[in]  table: crc calculate table.
 * @param[in]  len: data length.
 * @return     crc result.
 */
unsigned long crc32_cal(unsigned long crc, unsigned char *input, unsigned long *table, int len);


#endif /* OTA_H_ */
